Conversation
|
No major YANG version changes in commit 1095666 |
|
Regarding the proposal to introduce a generic list of top-level configurable I realize the desire here due to how such a named counter is referenced from other subtrees or accessed but speaking on behalf of JUNOS/EVO, this is not how this feature is implemented and named counters cannot be shared across references or domains and may also get derived names depending on if interface granularity is tagged. As it stands in current implementation, this would result in phantom alien config nodes that have no real meaning and could give the perception of conformance for specific use on state only as I see it. |
|
Arista EOS supports user-counters ( we call them named counters ), which are scoped strictly within individual policies. As shown in the below examples, these counters must be defined under a policy to take effect in accounting. The current proposal do not align with EOS implementation. By defining user-counters in the top-level tree, it implies they are global objects that can be shared across separate policies or other future entities that might use them. |
|
Given the feedback, I'll restructure this to add named counters in-line with policy-forwarding policies. I am thinking something like: |
These are counter-data paths. I’m assuming the entire user-counter* tree falls under the policy definition as well. Please clarify if that’s not the case. |
|
Revised user-counters to be a container per policy and updated the PR description text and tree view. This still aligns with the operational use case and aligns better with referenced implementations which have "per policy" user defined counters. In order to facilitate the creation of an 'anchor point' where the counter values can be subscribed to for streaming, this PR creates a |
|
@amitarista @earies @jsterne @rgwilton for your comments on the revised model |
|
In JUNOS/EVO - there is no pre-definition of counter names that are referenced elsewhere. But rather counter names are marked as inline actions. For the simplest use-cases, the proposed modeling here could be accepted w/ the predefined names as "phantom" config nodes that have no relevance that are then marked as actions. The state could be reflected in similar fashion. e.g. For inline defined counter But the most common operational use-case is the desire for "interface-specific" counters which means the name of the counter that is defined inline is expanded to a different name based on the interface e.g. For inline defined counter The latter case cannot be covered in this scenario as counter names are derived and thus leafref validation would fail |
|
To add to the comment on the OC Operators call 2026-02-05 This is proposing an action of With this proposal defining an opaque counter64 It would be helpful to understand where these nodes fall short, if the intention is to deprecate and whether or not each rule should have an implicit counter enabled or not (for performance reasons) |
|
I'll make changes to
+--rw network-instance* [name]
+--rw policy-forwarding
+--rw policies
+--rw policy* [policy-id]
+--rw rules
+--rw rule* [sequence-id]
+--ro state
+--ro sequence-id? uint32
+ x--ro matched-pkts? oc-yang:counter64
+ x--ro matched-octets? oc-yang:counter64 |
EOS defines user-counters explicitly before they are used. |
Because there are (reconcilable) differences between implementations on this point, we will get operator consensus on the most operator friendly approach and choose a direction to go with the OC Model. Scheduled for OC operator review on Feb 24, 2026 |
|
Among the referenced implementations, one native implementation requires a counter to be defined as an action without any other configuration and implicitly creates telemetry entities. In a second implementation, the counters are required to be explicitly declared and then used within policy actions. To satisfy leafref requirements from a config node to a config node, it seems cleaner to have the policy-forwarding action |
If we step back from current implementations, as an operator - what does this pre-definition/reference buy anything other than the expense of additional nodes and bytes I'm curious? There are other areas where it essentially means duplicates or referenced values must be in place thus meaning implementations must either be strict per YANG or relax such enforcements. The opposite could also be that for an implementation that requires pre-definition and reference that it be handled by abstraction. No matter which direction, it poses complexity, true misalignment and potential corner cases ime but would rather go back to the operational benefits first. (Having seen too many instances where payloads are not properly formed per similar expectations) |
IMHO defining counters via config is not only cleaner and consistent with our other models, but it also benefits operators by allowing a single counter to be referenced across multiple rules within a policy. |
That may not be how other implementations work today so modeling aside - is this driving an implementation behavior that is warranted to change or is essentially a new feature is the question. Would like to hear from a few other implementations - @rgwilton @jsterne as well |
|
Discussed at OC Operators Meeting on Feb 24, 2026: Seems there's some ongoing discussion on the implementation details, though folks seem on board with the addition to the model. Will allow folks to add input until next the community meet next week. (and then we'll merge at the next operators meet, if there are no objections.) |
|
I'm not certain I'm following all the back and forth, but it feels like a current implementation of a single vendor being proposed here, and there is questionable value as earies brings up (other than nice alignment for a particular implementation). I don't think it will be very realistic to map this to other implementations so it would really be driving a significant change and new functionality in many other vendors (especially 1:N relationships are expected, e.g. multiple arbitrary refs to the same counter). |
Btw just to be clear, I'm not referring the EOS config here. I was citing the overall config-state pattern in the OpenConfig modeling. Reusability of the counter is applicable here since the same counter can be shared by multiple rules under a policy definition. Logical way to indicate this sharing is by making those rules point to the same counter entity via leafref. |
|
In OC modeling we are looking for at least 2 examples of existing implementations for a feature (but not a particular native configuration style) or assertion from operator(s) that feature requests are in progress with multiple implementors. We clearly have at least three pre-existing implementations of counters for policy-forwarding rules, noted below. This is not a vendor proprietary feature. The configuration schemas are indeed all different. Getting to a common schema is one of the key goals of OC and doing so means there's going to be some changes needed to adapt. Comments should be directed regarding the functionality of what is being proposed. Secondarily, if we can make the single OC model easier for multiple implementations, that is a nice to have benefit. Here are 4 references I've researched. Arista EOS traffic policy counters Simplified example: Cisco IOS XR implements ACL rules for packet matching in policy based forwarding. Those ACL rules can expose counters in the policybased routing and ACL based forwarding features (which are most similar to OC's "policy-forwarding" model here. So IOS XR does implement counters for matching rules, but the schema is rather different from other implementations and this model. JunOS filter based forwardingNokia SR Linux |
release/models/policy-forwarding/openconfig-pf-forwarding-policies.yang
Outdated
Show resolved
Hide resolved
release/models/policy-forwarding/openconfig-pf-forwarding-policies.yang
Outdated
Show resolved
Hide resolved
|
@dplore I think the failing CI checks are from openconfig/models-ci#112 ?? (Nvm: seems to have been failing before then...) New thought is https://pkg.go.dev/golang.org/x/tools 0.43 came out and needs Go 1.25 . |
|
On the debate about whether the counters should be predefined or added as state.. It's important to think about a use case where the same policy is applied to multiple interfaces. In this situation you could want one shared counter X to be incremented by packets matching the rule on all the applied interfaces or you could want per-interface, per-rule counters X1, X2, .. Xn. Both approaches can provide this choice, but they will do it differently: With pre-configured counter names, the policy-counter itself needs a configuration property to indicate if it is to be used as a single shared counter, or a template for creating per-interface counters. With auto-created counter names, the count X action in the policy-forwarding rule needs to say whether to use the shared counter with name X or whether to create a new interface-specific counter like X-ethernet1/1. Both proposals end up in a situation where you have at least some (if not all) counters only being in state and not config. |
Change Scope
user-counterswithin the/network-instances/network-instance/policy-forwarding/policysubtree.Platform Implementations
Arista EOS and Juniper JunOS each have packet counter actions for their traffic-policy and filter based forwarding respectively.
Arista EOS traffic policies
JunOS filter based forwarding
See #1371 for additional implementation references and example operational use cases.
The CLI semantics are different in that action to perform a count and the user named counter are both created with a single line of CLI. In OC, we need a way to create the counter and stream the state of the counter. The user-defined counters container is added at the
/network-instances/network-instance/policy-forwarding/policysubtree, allowing counters to be defined per policy. Each rule within the policy may define anactiontocountpackets matching the rule.Tree View
diff -wU 20 ~/old-tree.txt ~/pfcounter-tree.txt
+--rw policy-forwarding | +--rw config | | +--rw global-decap-policy? string | +--ro state | | +--ro global-decap-policy? string | +--rw policies | | +--rw policy* [policy-id] | | +--rw policy-id -> ../config/policy-id + | | +--rw policy-counters + | | | +--rw policy-counter* [name] + | | | +--rw name -> ../config/name + | | | +--rw config + | | | | +--rw name? string + | | | +--ro state + | | | +--ro name? string + | | | +--ro counters + | | | +--ro packets? oc-yang:counter64 + | | | +--ro bytes? oc-yang:counter64 | | +--rw config | | | +--rw policy-id? string | | | +--rw type? enumeration | | +--ro state | | | +--ro policy-id? string | | | +--ro type? enumeration | | +--rw rules | | +--rw rule* [sequence-id] | | +--rw sequence-id -> ../config/sequence-id | | +--rw config | | | +--rw sequence-id? uint32 | | +--ro state | | | +--ro sequence-id? uint32 | | | +--ro matched-pkts? oc-yang:counter64 | | | +--ro matched-octets? oc-yang:counter64 | | +--rw l2 | | | +--rw config | | | | +--rw source-mac? oc-yang:mac-address | | | | +--rw source-mac-mask? oc-yang:mac-address | | | | +--rw destination-mac? oc-yang:mac-address @@ -3653,53 +3663,55 @@ | | | +--rw config | | | | +--rw source-port? oc-pkt-match-types:port-num-range | | | | +--rw source-port-set? -> /oc-sets:defined-sets/port-sets/port-set/name | | | | +--rw destination-port? oc-pkt-match-types:port-num-range | | | | +--rw destination-port-set? -> /oc-sets:defined-sets/port-sets/port-set/name | | | | +--rw detail-mode? enumeration | | | | +--rw explicit-detail-match-mode? enumeration | | | | +--rw explicit-tcp-flags* identityref | | | | +--rw builtin-detail? enumeration | | | +--ro state | | | +--ro source-port? oc-pkt-match-types:port-num-range | | | +--ro source-port-set? -> /oc-sets:defined-sets/port-sets/port-set/name | | | +--ro destination-port? oc-pkt-match-types:port-num-range | | | +--ro destination-port-set? -> /oc-sets:defined-sets/port-sets/port-set/name | | | +--ro detail-mode? enumeration | | | +--ro explicit-detail-match-mode? enumeration | | | +--ro explicit-tcp-flags* identityref | | | +--ro builtin-detail? enumeration | | +--rw action | | | +--rw config + | | | | +--rw count? -> ../../../../../policy-counters/policy-counter/config/name | | | | +--rw discard? boolean | | | | +--rw decapsulate-gre? boolean | | | | +--rw decap-network-instance? -> /network-instances/network-instance/config/name | | | | +--rw decap-fallback-network-instance? -> /network-instances/network-instance/config/name | | | | +--rw post-decap-network-instance? -> /network-instances/network-instance/config/name | | | | +--rw network-instance? -> /network-instances/network-instance/config/name | | | | +--rw path-selection-group? -> ../../../../../../../path-selection-groups/path-selection-group/config/group-id | | | | +--rw next-hop? oc-inet:ip-address | | | | +--rw next-hop-group? -> ../../../../../../../../static/next-hop-groups/next-hop-group/config/name | | | | +--rw decapsulate-mpls-in-udp? boolean | | | | +--rw decapsulate-gue? boolean | | | | +--rw ip-ttl? uint8 | | | +--ro state + | | | | +--ro count? -> ../../../../../policy-counters/policy-counter/config/name | | | | +--ro discard? boolean | | | | +--ro decapsulate-gre? boolean | | | | +--ro decap-network-instance? -> /network-instances/network-instance/config/name | | | | +--ro decap-fallback-network-instance? -> /network-instances/network-instance/config/name | | | | +--ro post-decap-network-instance? -> /network-instances/network-instance/config/name | | | | +--ro network-instance? -> /network-instances/network-instance/config/name | | | | +--ro path-selection-group? -> ../../../../../../../path-selection-groups/path-selection-group/config/group-id | | | | +--ro next-hop? oc-inet:ip-address | | | | +--ro next-hop-group? -> ../../../../../../../../static/next-hop-groups/next-hop-group/config/name | | | | +--ro decapsulate-mpls-in-udp? boolean | | | | +--ro decapsulate-gue? boolean | | | | +--ro ip-ttl? uint8 | | | +--rw encapsulate-gre | | | | +--rw config | | | | | +--rw identifying-prefix? oc-inet:ip-prefix | | | | +--ro state | | | | | +--ro identifying-prefix? oc-inet:ip-prefix | | | | +--rw targets | | | | +--rw target* [id] | | | | +--rw id -> ../config/id